package nl.tue.be.ds.duraark.bSDD.dump;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import com.sun.jersey.api.client.UniformInterfaceException;

public class ConSearchProcessor {
	public static final int MaxThreadNum = 8000;
	public static final int MaxTaskNum = 200000;
	public static final int MaxSearchTermLength = 16;

	public static List<Future<Integer>> futureList;
	public static ThreadPoolExecutor patternSearchPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(MaxThreadNum);
	private ExecutorService termSearchPool = Executors.newFixedThreadPool(1000);
	
	
	public static boolean isTaskTooMany(){
		long submitted = patternSearchPool.getTaskCount();
		long completed = patternSearchPool.getCompletedTaskCount();
		long notCompleted = submitted - completed;
		
		return notCompleted>MaxTaskNum;
	}
	
	private Future<Integer> postSearchCallPerTerm(String searchTerm){

		ConSearchPerTermCallable callable = new ConSearchPerTermCallable(searchTerm);
		Future<Integer> future = termSearchPool.submit(callable);

		return future;
	}
	
	public static Future<Integer> postSearchCallPerTermPattern(String searchTerm, boolean isTaskTooMany){
			
		System.out.println("pattern search Term : " + searchTerm + " Term length : " + searchTerm.length());
		ConSearchPerTermPatternCallable callable = new ConSearchPerTermPatternCallable(searchTerm, isTaskTooMany);
		Future<Integer> future = patternSearchPool.submit(callable);
			
		return future;
	}
	
	private Integer getSearchCallPerTerm(Future<Integer> future) throws InterruptedException, ExecutionException  {	
	
		Integer integer = future.get();
		return integer;
	}
	
	private void exceptionProcess(Exception e){
		
		if (e.getCause().getCause() instanceof UniformInterfaceException) {
			UniformInterfaceException uifException = (UniformInterfaceException) e.getCause().getCause();
			
			switch (uifException.getResponse().getStatus()) {
			case 500:
				String failedSearchTerm = e.getCause().getMessage();

				if (failedSearchTerm.length() <= MaxSearchTermLength){
					Future<Integer> f = postSearchCallPerTerm(failedSearchTerm);
					futureList.add(f);
				}

				if (failedSearchTerm.length()< MaxSearchTermLength){
					for (char ch = 'a'; ch <= 'z'; ch++) {
						String newSearchTerm = failedSearchTerm + Character.toString(ch);
						Future<Integer> future = postSearchCallPerTermPattern(newSearchTerm, isTaskTooMany());
						futureList.add(future);
					}
				}
				break;
			case 503:
				String unavailableSearchTerm = e.getCause().getMessage();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				
				Future<Integer> future = postSearchCallPerTermPattern(unavailableSearchTerm, isTaskTooMany());
				futureList.add(future);
				break;
			default:
				e.printStackTrace();
			}

		} else {
			e.printStackTrace();
		}
	
	}
	
	public Integer searchPerTerm() {
		futureList = new ArrayList<Future<Integer>>();
		Integer sum = 0;
		
		for (char ch1 = 'a'; ch1 <= 'z'; ch1++) {
			String searchTerm = Character.toString(ch1);
			futureList.add(postSearchCallPerTermPattern(searchTerm, isTaskTooMany()));
		}
		
		for (int i =0; i < futureList.size(); i++) {
			Integer num = 0;
			System.out.println("In futureList " + (futureList.size() - i) + " future tasks left" );
			
			try {
				num = getSearchCallPerTerm(futureList.get(i));
				
			} catch (InterruptedException e) {
				
				e.printStackTrace();
				
			} catch (ExecutionException e) {
				exceptionProcess(e);
			}
			sum = sum + num;
		}

		termSearchPool.shutdown();
		patternSearchPool.shutdown();
		return sum;
	}
	
	
}
